home *** CD-ROM | disk | FTP | other *** search
- /*-------------------------------------*
- | File: TS.c - Text scroller routines |
- +-------------------------------------------------------------*
- | These routines were inspired from an example due to Martin |
- | Taillefer and published on AmigaMail; although the original |
- | routines have been heavily modified, I am in debt with M.T. |
- +---------------------------------------------------------+---*
- | Author: Maurizio Loreti, aka MLO or I3NOO. |
- | Address: University of Padova - Department of Physics |
- | Via F. Marzolo, 8 - 35131 PADOVA - Italy |
- | Phone: (39)(49) 844-313 FAX: (39)(49) 844-245 |
- | E-Mail: loreti@padova.infn.it (TCP/IP) |
- | Home: Via G. Donizetti 6 - 35010 CADONEGHE (PD) - Italy |
- *---------------------------------------------------------*/
-
- /**
- | #includes
- **/
-
- #include <stddef.h> /* Standard library */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <exec/types.h> /* AmigaDOS specific */
- #include <clib/graphics_protos.h>
- #include <clib/layers_protos.h>
- #include <clib/gadtools_protos.h>
- #include <clib/intuition_protos.h>
- #include "main.h" /* Local stuff */
- #include "ts.h"
- #include "ext.h"
-
- void AddLine(
- char *s,
- size_t n,
- BOOL update
- ){
- /**
- | Adds the string "s" ("n" bytes long) to our document:
- | a new "Line" structure is added to the linked list, and
- | filled; if "update" is TRUE, the text is scrolled to
- | display the last line and updated.
- **/
-
- Line *pL;
-
- if ((pL = malloc(sizeof(Line) + n)) == NULL) {
- Error("No memory for Line");
- }
-
- pL->sl_Length = n;
- strcpy(pL->sl_Text, s);
- pL->sl_Forw = NULL;
- if ((pL->sl_Back = lastLine) == NULL) {
- firstLine = pL;
- } else {
- lastLine->sl_Forw = pL;
- }
- lastLine = pL;
- numLines++;
-
- if (update) {
- if (numLines > linesVisible) {
- topLine = numLines - linesVisible;
- } else {
- topLine = 0;
- }
- UpdateScroller();
- }
- }
-
- void BusyState(
- BOOL state
- ){
- /**
- | Whenever the application is busy, this function should be called
- | as BusyState(TRUE); this will change the pointer to a default
- | OS 2.0 busy-pointer too, to tell the user that we are not
- | listening to the IDCMP's for awhile. When finished, call
- | BusyState(FALSE).
- **/
-
- static UWORD __chip waitPointer[] = {
- 0x0000, 0x0000, 0x0400, 0x07C0, 0x0000, 0x07C0, 0x0100, 0x0380,
- 0x0000, 0x07E0, 0x07C0, 0x1FF8, 0x1FF0, 0x3FEC, 0x3FF8, 0x7FDE,
- 0x3FF8, 0x7FBE, 0x7FFC, 0xFF7F, 0x7EFC, 0xFFFF, 0x7FFC, 0xFFFF,
- 0x3FF8, 0x7FFE, 0x3FF8, 0x7FFE, 0x1FF0, 0x3FFC, 0x07C0, 0x1FF8,
- 0x0000, 0x07E0, 0x0000, 0x0000
- };
-
- if (state == TRUE) {
- SetPointer(pWind, waitPointer, 16, 16, -6, 0);
- } else {
- ClearPointer(pWind);
- }
-
- if (pWind->WLayer->Flags & LAYERREFRESH) {
- RefreshView(TRUE);
- }
- }
-
- void ClearText(
- BOOL update
- ){
- /**
- | This procedure free()s all the linked list holding the
- | scrolled text. If "update" is TRUE, the window scrolling
- | region is really cleared.
- **/
-
- Line *pL;
-
- for (pL=firstLine; pL!=NULL; ) {
- Line *next = pL->sl_Forw;
-
- free(pL);
- pL = next;
- }
-
- firstLine = lastLine = NULL;
- numLines = topLine = 0;
-
- if (update) {
- SetScroller(pWind, pScroller, linesVisible, numLines, topLine);
- RefreshView(TRUE);
- }
- }
-
- void InitScroller(void)
- {
- /**
- | Scroller initialisation.
- | - memory is obtained to hold a copy of the window raster port to
- | be used for clearing (the originel raster port is used for
- | rendering); this speeds up these operations avoiding SetAPen() etc.
- | - some local global variables are initialised;
- | - the scrolling region is drawn (with the help text loaded in the
- | initialisation routines).
- **/
-
- memcpy(pClearRP, (pRP = pWind->RPort), sizeof(struct RastPort));
- SetDrMd(pClearRP, JAM2);
- SetAPen(pClearRP, 0);
- SetAPen(pRP, 1);
-
- fontWidth = pWind->RPort->Font->tf_XSize;
- fontHeight = pWind->RPort->Font->tf_YSize;
-
- bevelLeft = pWind->BorderLeft + BEVEL_LEFT;
- bevelTop = pWind->BorderTop + BEVEL_TOP;
- bevelWidth = BEVEL_WIDTH;
- bevelHeight = BEVEL_HEIGHT;
- textLeft = bevelLeft + TEXT_XOFFSET;
- textTop = bevelTop + TEXT_YOFFSET;
-
- viewWidth = (USHORT) (bevelWidth - 2 * (TEXT_XOFFSET) - 1);
- viewHeight = (USHORT) (bevelHeight - 2 * (TEXT_YOFFSET) - 1);
- columnsVisible = viewWidth / fontWidth;
- linesVisible = viewHeight / fontHeight;
- usefulWidth = (USHORT) (columnsVisible * fontWidth);
-
- RefreshView(TRUE);
- SetScroller(pWind, pScroller, linesVisible, numLines, topLine);
- }
-
- void LastLine(
- char *s,
- size_t n
- ){
- /**
- | A line is drawn at the end of the text, but NOT inserted
- | in the linked list; it will then be overdrawn from the next
- | AddLine()d or LastLine()d text; the text is scrolled if needed,
- | to display the bottom line.
- | LastLine() here is only used to display the
- | "reading track X head Y" text.
- | "s" is the string to be displayed, "n" bytes long.
- **/
-
- USHORT y;
-
- if (numLines >= linesVisible) {
- topLine = numLines - linesVisible + 1;
- UpdateScroller();
- y = linesVisible;
- } else {
- y = numLines - topLine + 1;
- }
- y = (USHORT) (textTop + pRP->TxBaseline + fontHeight * (y - 1));
- RenderLine(textLeft, y, usefulWidth, s, n);
- }
-
- void RefreshView(
- BOOL damage
- ){
- /**
- | This function performs most of the rendering work needed.
- | It looks at the current window size and adjusts its rendering
- | variables in consequence; then, if the "damage" parameter is
- | TRUE, this routine explicitly erases any area of the display
- | in which we will not be rendering in the rendering loop: this
- | erases any left over characters that could be there if the
- | user sizes or rearrange the window. Finally, the routine
- | determines which lines of the display need to be updated,
- | and goes on to do it.
- **/
-
- USHORT i;
- Line *pL;
- USHORT y;
-
- /**
- | What is the top line to be rendered?
- **/
-
- if (linesVisible > numLines) {
- usefulHeight = (USHORT) (numLines * fontHeight);
- topLine = 0;
- } else {
- usefulHeight = (USHORT) (linesVisible * fontHeight);
- if (topLine + linesVisible > numLines) {
- topLine = numLines - linesVisible;
- }
- }
-
- /**
- | If the layer has been damaged (and the window is to be refreshed),
- | this is handled now (the gadgetry is already OK at this moment).
- **/
-
- if (damage) {
- RectFill(pClearRP,
- bevelLeft - 1,
- bevelTop - 1,
- bevelLeft + bevelWidth,
- bevelTop + bevelHeight);
- DrawBevelBox(pRP,
- bevelLeft, bevelTop,
- bevelWidth, bevelHeight,
- GT_VisualInfo, pVI,
- TAG_END);
- }
-
- /**
- | Do we have something to render? If yes, we find the pointer to the
- | top line text, starting from the top or the bottom of the list.
- **/
-
- if (usefulHeight && usefulWidth) {
- int n;
-
- if ((n = numLines - (topLine + 1)) < topLine) {
- pL = ScanList(firstLine, topLine);
- } else {
- pL = ScanList(lastLine, -n);
- }
-
- y = (USHORT) (textTop + pRP->TxBaseline - fontHeight);
-
- if (damage || (topLine >= oldTopLine + linesVisible - 1) ||
- ((oldTopLine > linesVisible) &&
- (topLine <= oldTopLine - linesVisible + 1))) {
- i = linesVisible;
- } else if (topLine < oldTopLine) {
- ScrollRaster(pRP,
- 0, -((long) (oldTopLine - topLine) * fontHeight),
- textLeft,
- textTop,
- textLeft + usefulWidth - 1,
- textTop + usefulHeight - 1);
-
- i = oldTopLine - topLine;
- } else if (topLine > oldTopLine) {
- ScrollRaster(pRP,
- 0, ((topLine - oldTopLine) * fontHeight),
- textLeft,
- textTop,
- textLeft + usefulWidth - 1,
- textTop + usefulHeight - 1);
-
- for (i = linesVisible - (topLine - oldTopLine);
- pL->sl_Forw != NULL && i;
- i--) {
- pL = pL->sl_Forw;
- }
-
- y += (USHORT) (fontHeight * (linesVisible - (topLine - oldTopLine)));
- i = topLine - oldTopLine;
- } else if (oldNumLines < numLines && numLines <= linesVisible) {
- for (i = oldNumLines; pL->sl_Forw != NULL && i; i--) {
- pL = pL->sl_Forw;
- }
-
- y += (USHORT) (fontHeight * oldNumLines);
- i = numLines - oldNumLines;
- } else {
- i = 0;
- }
-
- while (i-- && pL != NULL) {
- y += fontHeight;
- RenderLine(textLeft, y, usefulWidth, pL->sl_Text, pL->sl_Length);
- pL = pL->sl_Forw;
- }
- }
-
- oldTopLine = topLine;
- oldNumLines = numLines;
- }
-
- void SetTopLine(
- UWORD n
- ){
- /**
- | Sets the top line of the scroller text to "n".
- **/
-
- if (topLine != n) {
- topLine = n;
- RefreshView(FALSE);
- }
- }
-
- /*-------------------------- Local Procedures --------------------------*/
-
- static void RenderLine(
- USHORT x,
- USHORT y,
- USHORT w,
- char *text,
- size_t len
- ){
- /**
- | Render a single line of text ("text", "len" characters
- | long) at the given position "x","y" (pixels). "w" is the
- | length (pixels) of the rendering region.
- **/
-
- Move(pRP, x, y);
- if (len > columnsVisible) {
- len = columnsVisible;
- }
-
- (void) Text(pRP, text, len);
- if (len < columnsVisible) {
- RectFill(pClearRP,
- pRP->cp_x,
- y - pRP->TxBaseline,
- x + w - 1,
- y - pRP->TxBaseline + fontHeight - 1);
- }
- }
-
- static void SetScroller(
- struct Window *pW,
- struct Gadget *pG,
- USHORT lV,
- USHORT nL,
- USHORT tL
- ){
- /**
- | Adjust the scroller gadget to reflect the current setting:
- | "lV" lines visible, "nL" total lines and "tL" number of the
- | top line.
- **/
-
- GT_SetGadgetAttrs(pG, pW, NULL,
- GTSC_Visible, lV,
- GTSC_Total, nL,
- GTSC_Top, tL,
- TAG_DONE);
- }
-
- static Line *ScanList(
- register Line *pL,
- register int n
- ){
- register Line *pNew;
-
- if (n > 0) {
- while (n-- && (pNew = pL->sl_Forw) != NULL) pL = pNew;
- } else if (n < 0) {
- while (n++ && (pNew = pL->sl_Back) != NULL) pL = pNew;
- }
- return pL;
- }
-
- static void UpdateScroller(void)
- {
- /**
- | Updates the text scrolling region, reflecting
- | the current settings.
- **/
-
- SetScroller(pWind, pScroller, linesVisible, numLines, topLine);
- RefreshView(FALSE);
- }
-